import arrow
import re

from mongoengine import Q
from utilities.meta_view import APIView, APIViewList, APIViewDestroy
from django.http.response import FileResponse, Http404
from models.task import ScanTaskSessions
from models.target import Targets
from models.celery_task import CeleryTasks
from tasks import celery_app
from django.utils.encoding import escape_uri_path
from utilities.redis import captcha_redis as redis_conn
from utilities.meta_view import Response
from utilities.enums import (
    ReportTaskType,
    ReportExportStatus,
)
from utilities.utils import make_id
from utilities.djconsole import djconsole
from utilities.constant import REPORT_TPL_CHAPTERS
from tasks.report_export import report_export


def set_exhkey(key, val, ex=300):
    redis_conn.hmset(key, val)
    redis_conn.expire(key, ex)


class ReportExport(APIView):
    def post(self, request, *args, **kwargs):
        username = str(request.user.username)
        about = djconsole.get_license_detail(request).get("about", {})
        targets = request.data.get("targets", [])
        chapters = request.data.get("chapters", [])
        start_at = request.data.get("start_date")
        end_at = request.data.get("end_date")
        task_session_id = request.data.get("task_session_id", "")
        task_type = ReportTaskType.last_task.value
        if start_at or end_at:
            task_type = ReportTaskType.time_period_task.value

        if task_session_id:
            task_type = ReportTaskType.history_task.value
            task_session = (
                ScanTaskSessions.objects(task_session_id=task_session_id)
                .only("target_id", "started_at", "ended_at")
                .first()
            )
            target_id = task_session.target_id
            target = (
                Targets.objects(target_id=target_id)
                .only("target_url", "target_name", "target_title")
                .first()
            )
            targets = [
                {
                    "task_session_id": task_session_id,
                    "target_id": target_id,
                    "target_url": target.target_url,
                    "target_name": target.target_name or target.target_title,
                }
            ]
            start_at = task_session.started_at
            end_at = task_session.ended_at

        params = {
            "targets": targets,
            "chapters": chapters,
            "start_at": arrow.get(start_at).datetime
            if start_at
            else None,
            "end_at": arrow.get(end_at).datetime
            if end_at
            else None,
        }

        export_task_id = make_id()
        celery_task_data = {
            "export_task_id": export_task_id,
            "task_type": task_type,
            "params": params,
            "result": {
                "status": ReportExportStatus.waiting.value,
                "process": 0,
            },
            "operator": username,
            "user_id": request.user.user_id,
            "created_at": arrow.utcnow().datetime,
        }
        celery_tasks = CeleryTasks.from_dict(celery_task_data)
        celery_tasks.save()
        celery_task_id = report_export.delay(
            export_task_id, str(request.user.id), about
        )
        celery_tasks.celery_task_id = str(celery_task_id)
        celery_tasks.save()
        return Response({"data": {"export_task_id": export_task_id}})


class ReportExportList(APIViewList):
    def list(self):
        """获取报告导出列表"""
        target_url = self.request.GET.get("target_url", "")
        status = self.request.GET.get("status", "")
        page, limit = self.get_paginate()
        query = {**self.user_query}
        if target_url:
            query["params.targets.target_url"] = {"$regex": target_url}
        if status:
            query["result.status"] = status
        all_export_tasks = (
            CeleryTasks.objects.find(query)
            .order_by("-created_at").paginate(per_page=limit)
        )
        total = all_export_tasks.count
        export_tasks = list(all_export_tasks.page(page))
        results = []
        for export_task in export_tasks:
            result = {
                "export_task_id": export_task.export_task_id,
                "targets": export_task.params.targets,
                "monitored_at": {
                    "start_at": arrow.get(export_task.params.start_at).format("YYYY-MM-DD HH:mm:ss") if export_task.params.start_at else "",
                    "end_at": arrow.get(export_task.params.end_at).format("YYYY-MM-DD HH:mm:ss") if export_task.params.end_at else ""
                },
                "task_created_at": arrow.get(export_task.created_at)
                .to("Asia/Shanghai")
                .format("YYYY-MM-DD HH:mm:ss") if export_task.created_at else None,
                "report_created_at": arrow.get(export_task.result.created_at)
                .to("Asia/Shanghai")
                .format("YYYY-MM-DD HH:mm:ss") if export_task.result.created_at else None,
                "status": export_task.result.status,
                "progress": export_task.result.progress,
            }
            results.append(result)
        return Response({"data": results, "page": page, "total": total})


class ReportDelete(APIViewDestroy):
    def destroy(self):
        export_task_id_list = self.request.data.get("export_task_ids", [])
        celery_tasks = CeleryTasks.objects.filter(
            export_task_id__in=export_task_id_list
        )
        deleted_count = 0
        if celery_tasks:
            for celery_task in celery_tasks:
                if celery_task.celery_task_id:
                    celery_app.control.revoke(
                        celery_task.celery_task_id, terminate=True
                    )
                deleted_count += CeleryTasks.objects(
                    pk=celery_task.id
                ).delete()
        else:
            raise Http404
        return Response({"deleted_count": deleted_count})


class ReportDownload(APIView):
    def get(self, request, *args, **kwargs):
        export_task_id = self.request.GET.get("export_task_id", "")
        about = djconsole.get_license_detail(self.request).get("about", {})
        celery_task = CeleryTasks.objects.filter(
            export_task_id=export_task_id
        ).first()
        file = celery_task.result.file
        file_type = celery_task.result.file_type
        filename = celery_task.result.filename
        if not file or not filename:
            raise Http404

        filename = re.sub(r"[,]", "", filename)
        if filename.startswith("【"):
            filename = "".join(filename.split("】", maxsplit=1)[-1])
        file.seek(0)
        attachment = f"{filename} {about.get('product_nickname_cn', '')} 安全监测报告.{file_type}"
        response = FileResponse(file, filename=escape_uri_path(attachment))

        response["Content-Disposition"] = "attachment;filename={}".format(
            escape_uri_path(attachment)
        )
        return response


class ReportTargetList(APIViewList):
    def list(self):
        target_url = self.request.GET.get("target_url", "")
        target_name = self.request.GET.get("target_name", "")
        query = Q(**self.user_query)
        if target_name:
            query = query & (
                Q(target_name__contains=target_name)
                | (Q(target_name='') & Q(target_title__contains=target_name))
            )
        if target_url:
            query = query & Q(target_url__contains=target_url)

        targets = (
            Targets.objects.only("target_url", "target_name", "target_id", "target_title")
            .filter(query)
            .order_by("-updated_at")
        )
        total = targets.count()
        results = []
        for target in targets:
            result = {
                "target_id": target.target_id,
                "target_url": target.target_url,
                "target_name": target.target_name or target.target_title,
            }
            results.append(result)
        return Response({"data": results, "total": total})


class ReportChapterList(APIViewList):
    def list(self):
        return Response(
            {
                "data": [{k: v} for k, v in REPORT_TPL_CHAPTERS.items()],
                "total": len(REPORT_TPL_CHAPTERS)
            }
        )
